package com.rf.richfitwheel.workflow.service.impl;

import com.rf.richfitwheel.admin.sys.model.OrgHasParent;
import com.rf.richfitwheel.admin.sys.model.OrgVO;
import com.rf.richfitwheel.admin.sys.vo.UserVO;
import com.rf.richfitwheel.common.contants.Constant;
import com.rf.richfitwheel.common.exception.BusinessException;
import com.rf.richfitwheel.common.utils.UuidUtil;
import com.rf.richfitwheel.workflow.contants.StationProcessContant;
import com.rf.richfitwheel.workflow.dao.WfAuthRuleMapper;
import com.rf.richfitwheel.workflow.dao.WfStationProcessMapper;
import com.rf.richfitwheel.workflow.dao.WfStationProcessOrderMapper;
import com.rf.richfitwheel.workflow.dao.WfStationProcessParPubMapper;
import com.rf.richfitwheel.workflow.feignclient.SysMsgStreamFeignService;
import com.rf.richfitwheel.workflow.feignclient.SysOrgFeignService;
import com.rf.richfitwheel.workflow.model.*;
import com.rf.richfitwheel.workflow.service.ModelService;
import com.rf.richfitwheel.workflow.service.WfProcessFolderService;
import com.rf.richfitwheel.workflow.service.WfStationProcessOrderService;
import com.rf.richfitwheel.workflow.service.WfStationProcessService;
import lombok.RequiredArgsConstructor;
import net.sf.json.JSONArray;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.activiti.engine.repository.Model;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service("wfStationProcessService")
@RequiredArgsConstructor
public class WfStationProcessServiceImpl implements WfStationProcessService {

    private final WfStationProcessMapper wfStationProcessMapper;

    private final WfProcessFolderService wfProcessFolderService;

    private final WfStationProcessOrderService wfStationProcessOrderService;

    private final ModelService modelService;
    @Autowired
    private SysOrgFeignService sysOrgFeignService;
    @Autowired
    private SysMsgStreamFeignService sysMsgStreamFeignService;
    @Autowired
    private WfAuthRuleMapper wfAuthRuleMapper;
    @Autowired
    private WfStationProcessOrderMapper wfStationProcessOrderMapper;
    @Autowired
    private WfStationProcessParPubMapper wfStationProcessParPubMapper;
    @Override
    public WfStationProcess selectByOrgCodeAndFolderCode(String orgCode, String folderCode) {
        WfStationProcessExample example = new WfStationProcessExample();
        WfStationProcessExample.Criteria criteria = example.createCriteria();
        criteria.andOrgCodeEqualTo(orgCode);
        criteria.andFolderCodeEqualTo(folderCode);
        //example.setOrderByClause(" order_num ");
        List<WfStationProcess> list = wfStationProcessMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }
    
    /**
     * 保存并发布流程，这段代码是我写过有史以来最恶心的
     * @param param
     * @param userVO
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndPublishWfStationProcess(String param, UserVO userVO) throws Exception {
        JSONObject jsonObject = JSONObject.fromObject(param);
        JSONObject formJsonObj = jsonObject.getJSONObject("dataForm");
        String orgCode = formJsonObj.getString("orgCode");
        String orgName = formJsonObj.getString("orgName");
        String folderCode = formJsonObj.getString("folderCode");
        String parSub = formJsonObj.getString("parSub");
        String ruleCondition = formJsonObj.getString("ruleCondition");
        WfProcessFolder wfProcessFolder = wfProcessFolderService.selectByFolderCode(folderCode);//获取流程对应的目录
        WfStationProcess wfStationProcess = this.selectByOrgCodeAndFolderCode(orgCode, folderCode);
        if (ObjectUtils.isEmpty(wfStationProcess)) {
            Date nowDate = new Date();
            wfStationProcess = new WfStationProcess();
            wfStationProcess.setId(UuidUtil.get32UUID());
            wfStationProcess.setVersion(0);
            wfStationProcess.setOrgCode(orgCode);
            wfStationProcess.setOrgName(orgName);
            wfStationProcess.setFolderCode(wfProcessFolder.getFolderCode());
            wfStationProcess.setModuleType(wfProcessFolder.getModuleType());
            wfStationProcess.setCreater(userVO.getId());
            wfStationProcess.setCreateTime(nowDate);
            wfStationProcess.setModTime(nowDate);
            wfStationProcess.setParSub(parSub);
            wfStationProcess.setModUser(userVO.getId());
            if(StationProcessContant.ParSubType.CONDITIONAL.getValue().equals(parSub)){
                wfStationProcess.setRuleCondition(ruleCondition);
            }else{
                wfStationProcess.setRuleCondition(null);
            }
            wfStationProcessMapper.insert(wfStationProcess);
        } else {
            wfStationProcess.setVersion(wfStationProcess.getVersion() + 1);
            wfStationProcess.setOrgCode(orgCode);
            wfStationProcess.setOrgName(orgName);
            wfStationProcess.setFolderCode(wfProcessFolder.getFolderCode());
            wfStationProcess.setModuleType(wfProcessFolder.getModuleType());
            wfStationProcess.setModTime(new Date());
            wfStationProcess.setModUser(userVO.getId());
            wfStationProcess.setParSub(parSub);
            if(StationProcessContant.ParSubType.CONDITIONAL.getValue().equals(parSub)){
                wfStationProcess.setRuleCondition(ruleCondition);
            }else{
                wfStationProcess.setRuleCondition(null);
            }
            wfStationProcessMapper.updateByPrimaryKey(wfStationProcess);//更新当前岗位流程是否使用通用流程
        }
        JSONArray stationDataList = jsonObject.getJSONArray("stationDataList");
        if (stationDataList.size() == 0) {
            // 如果没有岗位记录则认为要删掉该流程
            wfStationProcessOrderService.deleteByStationProcessId(wfStationProcess.getId());
            wfStationProcessMapper.deleteByPrimaryKey(wfStationProcess.getId());
            return;
        }
        //给下级设置特殊分级授权规则,删除再新增
        WfStationProcessParPubExample example = new WfStationProcessParPubExample();
        WfStationProcessParPubExample.Criteria criteria = example.createCriteria();
        criteria.andStationProcessIdEqualTo(wfStationProcess.getId());
        wfStationProcessParPubMapper.deleteByExample(example);
        JSONArray parSubList = formJsonObj.getJSONArray("parSubList");
        for(Object o : parSubList){
            WfStationProcessParPub parPub = (WfStationProcessParPub) JSONObject.toBean(JSONObject.fromObject(o), WfStationProcessParPub.class);
            parPub.setId(UuidUtil.get32UUID());
            parPub.setStationProcessId(wfStationProcess.getId());
            wfStationProcessParPubMapper.insert(parPub);
        }
        // 看看有没有上级给设置的授权条件，如果有则给本级自定义的最后一个岗位设置分级授权
        OrgVO orgVO = sysOrgFeignService.getOrgVOObjectByOrgCode(orgCode);
        if(orgVO != null && orgVO.getParentOrg() != null){
            //找到本级的最后一个节点
            int index = 0;
            for(int i = 0; i < stationDataList.size(); i++){
                JSONObject stationData = stationDataList.getJSONObject(i);
                String isSourceP = (stationData.containsKey("sourceFrom") && stationData.get("sourceFrom") != null && !(stationData.get("sourceFrom") instanceof JSONNull)) ? stationData.getString("sourceFrom") : null;
                if("1".equals(isSourceP)){
                    index = i - 1;
                    break;
                }
            }
            OrgHasParent pTree = sysOrgFeignService.getOrgListByOrgIdUpHasNoSelfWithTree(orgVO.getParentOrg().getId());
            if(pTree != null){
                reloadFromUpOrgStations(stationDataList, pTree, index, folderCode, orgVO.getId());
            }else {
                if(index >= 0){
                    stationDataList.getJSONObject(index).put("authRules", null);
                    stationDataList.getJSONObject(index).put("lastStation", Constant.COMMON_YES_OR_NO_YES);
                }
            }
        }
        //岗位流程顺序
        List<WfStationProcessOrder> wfStationProcessOrders = wfStationProcessOrderService.saveWfStationProcessOrderAndReturnList(stationDataList, wfStationProcess, userVO);//保存岗位流程顺序

        Model templateModel = modelService.findByProcessKey("process_template_" + wfStationProcessOrders.size());//获取流程模型扩展
        if (ObjectUtils.isEmpty(templateModel)) {
            throw new BusinessException("流程模块[process_template_" + wfStationProcessOrders.size() + "]不存在!");
        }
        WfStationProcess wsp = this.selectByOrgCodeAndFolderCode(orgCode, folderCode);
        publishWfStationProcess(wfProcessFolder, wsp, templateModel, wfStationProcessOrders, userVO);
        //给下级系统管理员发消息
        /*WfStationProcess finalWfStationProcess = wfStationProcess;
        Thread threadOne = new Thread(() -> {
            OrgRoles orgRoles = new OrgRoles(orgCode, new String[]{"fcad66f3e7004536a18a0235b15b2afc"},
                    "上级机构已经更新了[" + wfProcessFolder.getFolderName() + "]流程审批岗位，请您在本级对应流程中重载上级设置岗位并重新发布流程。",
                    finalWfStationProcess.getId());
            sysMsgStreamFeignService.sendMsgToChildrenOrgRole(orgRoles);
        });
        threadOne.start();*/
        if(orgVO != null){
            //改策略了，上级发布后直接自动处理下级的流程节点并发布，启动一个线程通过递归方式处理
            Thread threadOne = new Thread(new ReloadChildrenStationProcess(wfStationProcessMapper,
                    wfProcessFolderService,
                    wfStationProcessOrderService,
                    modelService,
                    sysOrgFeignService,
                    wfAuthRuleMapper,
                    wfStationProcessOrderMapper,
                    orgVO.getId(),
                    orgVO.getOrgCode(),
                    folderCode,
                    wfProcessFolder.getFolderName(),
                    userVO,
                    wfStationProcessParPubMapper));
            threadOne.start();
        }
    }
    
    /**
     * @param stationDataList 岗位列表
     * @param pTree           机构
     * @param index           本级最后一个节点
     * @param realOrgId       当前机构id
     * @return 没啥用的返回值
     */
    private boolean reloadFromUpOrgStations(JSONArray stationDataList, OrgHasParent pTree, int index, String folderCode, String realOrgId){
        WfStationProcess wfStationProcessPar = selectByOrgCodeAndFolderCode(pTree.getOrgCode(), folderCode);
        if(wfStationProcessPar != null){
            //先看看上级有没有为自己指定参与条件，有多条只取其中一条,然后用这个条件去替换主设置
            WfStationProcessParPubExample exampleParent = new WfStationProcessParPubExample();
            WfStationProcessParPubExample.Criteria criteriaParent = exampleParent.createCriteria();
            criteriaParent.andStationProcessIdEqualTo(wfStationProcessPar.getId());
            criteriaParent.andOrgIdEqualTo(realOrgId);
            List<WfStationProcessParPub> pl = wfStationProcessParPubMapper.selectByExample(exampleParent);
            if(!pl.isEmpty()){
                wfStationProcessPar.setParSub(pl.get(0).getParSub());
                wfStationProcessPar.setRuleCondition(pl.get(0).getRuleCondition());
            }
            if(StationProcessContant.ParSubType.CONDITIONAL.getValue().equals(wfStationProcessPar.getParSub())){
                //有条件参与
                String ruleConditionPar = "!(" + wfStationProcessPar.getRuleCondition() + ")";
                if(index >= 0){
                    WfAuthRule wfAuthRule = new WfAuthRule();
                    wfAuthRule.setRuleType("2");
                    wfAuthRule.setRuleCondition(ruleConditionPar);
                    wfAuthRule.setToStationId("end");
                    JSONObject jObj = JSONObject.fromObject(wfAuthRule);
                    JSONArray jAar = new JSONArray();
                    jAar.add(jObj);
                    stationDataList.getJSONObject(index).put("authRules", jAar);
                    stationDataList.getJSONObject(index).put("lastStation", Constant.COMMON_YES_OR_NO_YES);
                }
                return true;
            }else if(StationProcessContant.ParSubType.UNCONDTIONNAL.getValue().equals(wfStationProcessPar.getParSub())){
                //无条件参与，给一个永远为false的规则，机智如我！
                String ruleConditionPar = "1 < 0";
                if(index >= 0){
                    WfAuthRule wfAuthRule = new WfAuthRule();
                    wfAuthRule.setRuleType("2");
                    wfAuthRule.setRuleCondition(ruleConditionPar);
                    wfAuthRule.setToStationId("end");
                    JSONObject jObj = JSONObject.fromObject(wfAuthRule);
                    JSONArray jAar = new JSONArray();
                    jAar.add(jObj);
                    stationDataList.getJSONObject(index).put("authRules", jAar);
                    stationDataList.getJSONObject(index).put("lastStation", Constant.COMMON_YES_OR_NO_YES);
                }
                return true;
            }else{
                //先啥也不干,在继续回调往上找
            }
        }
        if(pTree.getParent() != null){
            return reloadFromUpOrgStations(stationDataList,pTree.getParent(), index, folderCode, pTree.getId());
        }else{
            if(index >= 0){
                stationDataList.getJSONObject(index).put("authRules", null);
                stationDataList.getJSONObject(index).put("lastStation", Constant.COMMON_YES_OR_NO_YES);
            }
            return true;
        }
    }
    
    public void publishWfStationProcess(WfProcessFolder wpf, WfStationProcess wfStationProcess, Model templateModel, List<WfStationProcessOrder> wfStationProcessOrders, UserVO userVO) throws Exception {
        String templateModelId = templateModel.getId(), modelId, orgCode, processName, processKey, processCode;
        Model model = modelService.findByOrgCodeAndProcessCode(wfStationProcess.getOrgCode(), wpf.getFolderCode());
        if (ObjectUtils.isEmpty(model)) {//第一次发布,新增一个模型扩展
            orgCode = wfStationProcess.getOrgCode();
            processName = wpf.getFolderName();
            processKey = "wf_" + wfStationProcess.getOrgCode().replaceAll("#", ".") + "_" + wpf.getFolderCode();
            processCode = wpf.getFolderCode();
            model = modelService.newModel(orgCode, processName, processKey, processCode, userVO);
        }
        model.setName(wpf.getFolderName());
        Model newModel = modelService.copyModel(templateModelId, model.getId(), model.getOrgCode(), model.getName(), model.getKey(), model.getProcessCode(), wfStationProcessOrders);//复制模型

        modelService.deployModelExtendAndSetAuthor(newModel, wfStationProcess, userVO, wfStationProcessOrders);//根据模板发布流程

    }

    @Override
    public List<WfStationProcess> selectByModuleTypeAndOrgCode(String moduleType, String orgCode) {
        WfStationProcessExample example = new WfStationProcessExample();
        WfStationProcessExample.Criteria criteria = example.createCriteria();
        criteria.andOrgCodeEqualTo(orgCode);
        criteria.andModuleTypeEqualTo(moduleType);
        List<WfStationProcess> wfStationProcesses = wfStationProcessMapper.selectByExample(example);
        return wfStationProcesses;
    }
    
    /**
     * 获取单独为下级设置的参与条件
     *
     * @param stationProcessId 岗位流程id
     * @return 参与条件列表
     */
    @Override
    public List<WfStationProcessParPub> getWfStationProcessParPubByStationProcessId(String stationProcessId){
        WfStationProcessParPubExample example  = new WfStationProcessParPubExample();
        WfStationProcessParPubExample.Criteria criteria = example.createCriteria();
        criteria.andStationProcessIdEqualTo(stationProcessId);
        return wfStationProcessParPubMapper.selectByExample(example);
    }
    
    /**
     * 通过当前机构编码查询上级给设置的流程岗位,上级没设置或不参与的继续向上查找直至顶级
     *
     * @param orgHasParent    当前机构
     * @param folderCode 流程目录编码
     * @return 流程岗位配置
     */
    @Override
    public List<WfStationProcessOrder> getParentStationOrders(OrgHasParent orgHasParent, String folderCode){
        if(orgHasParent.getParent() == null){
            return new ArrayList<>();
        }
        WfStationProcess wfStationProcess = selectByOrgCodeAndFolderCode(orgHasParent.getParent().getOrgCode(), folderCode);
        
        if(wfStationProcess == null){
            //上级没设置的情况下继续往上找
            return getParentStationOrders(orgHasParent.getParent(), folderCode);
        }else{
            String tempParSub = wfStationProcess.getParSub();
            //先看看上级有没有为自己特殊指定参与条件，有多条只取其中一条,然后用这个条件去替换主设置
            WfStationProcessParPubExample exampleParent = new WfStationProcessParPubExample();
            WfStationProcessParPubExample.Criteria criteriaParent = exampleParent.createCriteria();
            criteriaParent.andStationProcessIdEqualTo(wfStationProcess.getId());
            criteriaParent.andOrgIdEqualTo(orgHasParent.getId());
            List<WfStationProcessParPub> pl = wfStationProcessParPubMapper.selectByExample(exampleParent);
            if(!pl.isEmpty()){
                tempParSub = pl.get(0).getParSub();
            }
            if(StringUtils.isBlank(tempParSub) || StationProcessContant.ParSubType.NOPARTI.getValue().equals(wfStationProcess.getParSub())){
                //上级设置不参与的情况下继续往上找
                return getParentStationOrders(orgHasParent.getParent(), folderCode);
            }else{
                List<WfStationProcessOrder> wfStationProcessOrders = wfStationProcessOrderService.selectListByStationProcessId(wfStationProcess.getId());
                return wfStationProcessOrders.stream().peek(m -> {
                    WfAuthRuleExample example = new WfAuthRuleExample();
                    WfAuthRuleExample.Criteria criteria = example.createCriteria();
                    criteria.andStationProcessOrderIdEqualTo(m.getId());
                    List<WfAuthRule> authRules = wfAuthRuleMapper.selectByExample(example);
                    m.setAuthRules(authRules);
                    m.setAuthRuleCount(authRules.size());
                    m.setAuthRuleLoaded(true);
                    m.setId(null);
                    m.setSourceFrom("1");
                }).collect(Collectors.toList());
            }
        }
    }
    
    
}